package com.gitee.dolt.weixin.mp;

import cn.hutool.json.JSONUtil;
import com.gitee.dolt.weixin.mp.aspect.WxMpServiceAspect;
import com.gitee.dolt.weixin.mp.event.WxMpMsgSendLogListener;
import com.gitee.dolt.weixin.mp.handler.*;
import com.gitee.dolt.weixin.mp.handler.impl.*;
import com.gitee.dolt.weixin.mp.properties.WxMpProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxRuntimeException;
import me.chanjar.weixin.common.redis.JedisWxRedisOps;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.api.impl.WxMpTemplateMsgServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;

import java.util.List;
import java.util.stream.Collectors;

import static me.chanjar.weixin.common.api.WxConsts.EventType;
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;

/**
 * wechat mp configuration
 *
 * @author Binary Wang(https://github.com/binarywang)
 */
@RequiredArgsConstructor
@Configuration
@EnableConfigurationProperties(WxMpProperties.class)
@Slf4j
@ComponentScan(basePackages = "com.gitee.dolt.weixin.mp.controller")
public class WxMpAutoConfiguration {

    private final WxMpProperties properties;

    @Bean
    public LogHandler logHandler() {
        return new LogHandler();
    }

    @Bean
    public NullHandler nullHandler() {
        return new NullHandler();
    }

    @Bean
    @ConditionalOnMissingBean(KfSessionHandler.class)
    public KfSessionHandler kfSessionHandler() {
        return new DefaultKfSessionHandler();
    }

    @Bean
    @ConditionalOnMissingBean(StoreCheckNotifyHandler.class)
    public StoreCheckNotifyHandler storeCheckNotifyHandler() {
        return new DefaultStoreCheckNotifyHandler();
    }

    @Bean
    @ConditionalOnMissingBean(LocationHandler.class)
    public LocationHandler locationHandler() {
        return new DefaultLocationHandler();
    }

    @Bean
    @ConditionalOnMissingBean(MenuHandler.class)
    public MenuHandler menuHandler() {
        return new DefaultMenuHandler();
    }

    @Bean
    @ConditionalOnMissingBean(MsgHandler.class)
    public MsgHandler msgHandler() {
        return new DefaultMsgHandler();
    }

    @Bean
    @ConditionalOnMissingBean(UnsubscribeHandler.class)
    public UnsubscribeHandler unsubscribeHandler() {
        return new DefaultUnsubscribeHandler();
    }

    @Bean
    @ConditionalOnMissingBean(SubscribeHandler.class)
    public SubscribeHandler subscribeHandler() {
        return new DefaultSubscribeHandler();
    }

    @Bean
    @ConditionalOnMissingBean(ScanHandler.class)
    public ScanHandler scanHandler() {
        return new DefaultScanHandler();
    }

    @Bean
    public WxMpService wxMpService() {
        // 代码里 getConfigs()处报错的同学，请注意仔细阅读项目说明，你的IDE需要引入lombok插件！！！！
        final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
        if (configs == null) {
            throw new WxRuntimeException("大哥，拜托先看下项目首页的说明（readme文件），添加下相关配置，注意别配错了！");
        }

        WxMpService service = new WxMpServiceImpl();
        service.setTemplateMsgService(new WxMpTemplateMsgServiceImpl(service));

        service.setMultiConfigStorages(configs
                .stream().map(a -> {
                    WxMpDefaultConfigImpl configStorage;
                    if (this.properties.isUseRedis()) {
                        final WxMpProperties.RedisConfig redisConfig = this.properties.getRedisConfig();
                        JedisPool jedisPool = new JedisPool(redisConfig.getHost(), redisConfig.getPort());
                        configStorage = new WxMpRedisConfigImpl(new JedisWxRedisOps(jedisPool), a.getAppId());
                    } else {
                        configStorage = new WxMpDefaultConfigImpl();
                    }

                    configStorage.setAppId(a.getAppId());
                    configStorage.setSecret(a.getSecret());
                    configStorage.setToken(a.getToken());
                    configStorage.setAesKey(a.getAesKey());
                    return configStorage;
                }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
        return service;
    }

    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService,
                                           LogHandler logHandler,
                                           NullHandler nullHandler,
                                           KfSessionHandler kfSessionHandler,
                                           StoreCheckNotifyHandler storeCheckNotifyHandler,
                                           LocationHandler locationHandler,
                                           MenuHandler menuHandler,
                                           SubscribeHandler subscribeHandler,
                                           UnsubscribeHandler unsubscribeHandler,
                                           ScanHandler scanHandler,
                                           MsgHandler msgHandler) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);

        // 记录所有事件的日志 （异步执行）
        newRouter.rule().handler(logHandler).next();

        // 接收客服会话管理事件
        newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
                .handler(kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
                .handler(kfSessionHandler).end();
        newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
                .handler(kfSessionHandler).end();

        // 门店审核事件
        newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(storeCheckNotifyHandler).end();

        // 自定义菜单事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.CLICK).handler(menuHandler).end();

        // 点击菜单连接事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.VIEW).handler(nullHandler).end();

        // 关注事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.SUBSCRIBE).handler(subscribeHandler).end();

        // 取消关注事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.UNSUBSCRIBE).handler(unsubscribeHandler).end();

        // 上报地理位置事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.LOCATION).handler(locationHandler).end();

        // 接收地理位置消息
        newRouter.rule().async(false).msgType(EventType.LOCATION).handler(locationHandler).end();

        // 扫码事件
        newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(scanHandler).end();

        // 默认
        newRouter.rule().async(false).handler(msgHandler).end();

        return newRouter;
    }

    @Bean
    public WxMpServiceAspect wxMpServiceAspect() {
        return new WxMpServiceAspect();
    }

    @Bean
    @ConditionalOnMissingBean
    public WxMpMsgSendLogListener wxMpMsgSendLogListener() {
        return new WxMpMsgSendLogListener((optLogDTO) -> {
            log.debug("{}|{}", "WX_MP_MSG_SEND_LOG", JSONUtil.toJsonStr(optLogDTO));
        });
    }

}
